package com.xiaoshuidi.cloud.module.finance.framework.rpc.config;

import com.google.common.collect.Maps;
import com.xiaoshuidi.cloud.framework.pay.config.PayProperties;
import com.xiaoshuidi.cloud.framework.security.config.AuthorizeRequestsCustomizer;
import com.xiaoshuidi.cloud.module.bpm.api.task.BpmProcessInstanceApi;
import com.xiaoshuidi.cloud.module.contract.api.*;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinancePaymentApi;
import com.xiaoshuidi.cloud.module.member.api.coupon.CouponApi;
import com.xiaoshuidi.cloud.module.member.api.user.MemberUserApi;
import com.xiaoshuidi.cloud.module.rooms.api.apartment.ApartmentApi;
import com.xiaoshuidi.cloud.module.system.api.apartment.ApartmentManageApi;
import com.xiaoshuidi.cloud.module.system.api.sms.SmsSendApi;
import com.xiaoshuidi.cloud.module.system.api.user.AdminUserApi;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.Map;
import java.util.stream.Collectors;

@Configuration(proxyBeanMethods = false)
@Import(FeignClientsConfiguration.class)
@EnableFeignClients(clients = {ContractApi.class,
        MemberUserApi.class,
        CustomerCompanyApi.class,
        CouponApi.class,
        AdminUserApi.class,
        ContractOwnerOrderApi.class,
        ApartmentApi.class,
        ContractRentOrderApi.class,
        SmsSendApi.class,
        ContractRoomAccountApi.class,
        BpmProcessInstanceApi.class,
        ApartmentManageApi.class,
        ApprovalApi.class,
        OrderFeesApi.class
})
@RemoteApplicationEventScan({"com.xiaoshuidi.cloud.module.finance.mq.message", "com.xiaoshuidi.cloud.module.bpm.mq" +
        ".message"})
public class RpcConfiguration {
    @Bean("financeAuthorizeRequestsCustomizer")
    public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
        return new AuthorizeRequestsCustomizer() {
            @Override
            public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
                // Swagger 接口文档
                registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
                        .antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
                // Druid 监控
                registry.antMatchers("/druid/**").anonymous();
                // Spring Boot Actuator 的安全配置
                registry.antMatchers("/actuator").anonymous()
                        .antMatchers("/actuator/**").anonymous();
                // RPC 服务的安全配置
                registry.antMatchers("/rpc-api/**").permitAll();
                registry.antMatchers("/app-api/**").authenticated();
            }
        };
    }

    @Bean("financePaymentApiMap")
    public Map<String, FinancePaymentApi> financePaymentApiMap(Decoder decoder, Encoder encoder, Client client, Contract contract, PayProperties payProperties, ObjectProvider<RequestInterceptor> requestInterceptors) {
        Map<String, FinancePaymentApi> map = Maps.newHashMap();
        if (CollectionUtils.isEmpty(payProperties.getPaymentService())) {
            return Maps.newHashMap();
        }
        for (Map.Entry<String, String> e : payProperties.getPaymentService().entrySet()) {
            map.put(e.getKey(), Feign.builder()
                    .client(client)
                    .decoder(decoder)
                    .encoder(encoder)
                    .contract(contract)
                    .requestInterceptors(requestInterceptors.orderedStream().collect(Collectors.toList()))
                    .target(FinancePaymentApi.class, "http://" + e.getValue()));
        }
        return map;
    }

    @LoadBalanced
    @Bean("loadBalancedWebClientBuilder")
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}
